package com.sunwayworld.basemodule.business.pjtask.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.basemodule.business.pjreport.bean.LimsPjReportBean;
import com.sunwayworld.basemodule.business.pjreport.service.LimsPjReportService;
import com.sunwayworld.basemodule.business.pjtask.bean.LimsPjFolderBean;
import com.sunwayworld.basemodule.business.pjtask.bean.LimsPjFolderEquipBean;
import com.sunwayworld.basemodule.business.pjtask.bean.LimsPjTaskBean;
import com.sunwayworld.basemodule.business.pjtask.computing.PjTaskComputingEngine;
import com.sunwayworld.basemodule.business.pjtask.dao.LimsPjFolderEquiptDao;
import com.sunwayworld.basemodule.business.pjtask.service.LimsPjFolderEquiptService;
import com.sunwayworld.basemodule.business.pjtask.service.LimsPjFolderService;
import com.sunwayworld.basemodule.business.pjtask.service.LimsPjTaskService;
import com.sunwayworld.basemodule.common.auditrecord.service.LimsAuditRecordService;
import com.sunwayworld.basemodule.coredata.product.bean.LimsProductMainPuposeBean;
import com.sunwayworld.basemodule.coredata.product.service.LimsProductMainPuposeService;
import com.sunwayworld.basemodule.coredata.productreport.bean.LimsProductReportTemplateBean;
import com.sunwayworld.basemodule.coredata.productreport.bean.LimsReportClientProductBean;
import com.sunwayworld.basemodule.coredata.productreport.service.LimsProductReportTemplateService;
import com.sunwayworld.basemodule.coredata.productreport.service.LimsReportClientProductService;
import com.sunwayworld.cloud.lims.reporttemplate.service.LimsReportTemplateService;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.database.sql.Order;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsPjFolderEquiptServiceImpl implements LimsPjFolderEquiptService {

    @Autowired
    @Lazy
    LimsPjFolderService limsPjFolderService;

    @Autowired
    @Lazy
    LimsPjTaskService limsPjTaskService;

    @Autowired
    @Lazy
    LimsAuditRecordService limsAuditRecordService;

    @Lazy
    @Autowired
    private LimsProductMainPuposeService productMainPuposeService;

    @Lazy
    @Autowired
    private LimsPjReportService limsPjReportService;

    @Lazy
    @Autowired
    private LimsReportTemplateService limsReportTemplateService;

    @Lazy
    @Autowired
    private LimsReportClientProductService limsReportClientProductService;

    @Lazy
    @Autowired
    private LimsProductReportTemplateService limsProductReportTemplateService;

    @Autowired
    private LimsPjFolderEquiptDao limsPjFolderEquiptDao;

    @Override
    @SuppressWarnings("unchecked")
    public LimsPjFolderEquiptDao getDao() {
        return limsPjFolderEquiptDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsPjFolderEquipBean limsPjFolderEquipt = jsonWrapper.parseUnique(LimsPjFolderEquipBean.class);
        limsPjFolderEquipt.setId(ApplicationContextHelper.getNextIdentity());
        getDao().insert(limsPjFolderEquipt);
        return limsPjFolderEquipt.getId();
    }

    @Override
    @Transactional
    public JSONObject backToFolder(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> folderEquipBeans = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (folderEquipBeans.isEmpty()) {
            return req;
        }
        List<Long> ids = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
        folderEquipBeans = this.selectListByIds(ids);
        List<Long> folderIds = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getFolderId).collect(Collectors.toList());
        List<LimsPjFolderEquipBean> equipBeansAll = this.selectListByFilter(SearchFilter.instance().match("folderId", folderIds).filter(MatchPattern.OR));

        if (equipBeansAll.stream().anyMatch(e -> !e.getStatus().equals("logged"))) {
            req.put("message", I18nHelper.getMessage("BASEMODULE.PJ_FOLDER_BACK.STATUS_NOT_SAME"));
            req.put("flag", false);
            return req;
        }

//        List<LimsPjFolderBean> pjFolderBeans = limsPjFolderService.selectListByIds(folderIds);
        List<LimsPjTaskBean> pjTaskBeans = limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderId", folderIds).filter(MatchPattern.OR));

        LimsPjFolderBean update = new LimsPjFolderBean();
        update.setStatus("draft");
        limsPjFolderService.getDao().updateByIds(update, folderIds, "status");

        pjTaskBeans.forEach(pt -> {
            pt.setStatus("draft");
            pt.setFolderEquipId(null);
        });
        limsPjTaskService.getDao().fastUpdate(pjTaskBeans, "folderEquipId", "status");

        List<Long> delIds = equipBeansAll.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
        getDao().deleteByIdList(delIds);

        limsAuditRecordService.insertAuditRecords(folderIds, "T_LIMS_PJ_FOLDER", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_ENTER"), I18nHelper.getMessage("MODULE.BUSINESS.RESULT.BUTTON.RETURNBACK"), "");
        return req;
    }

    @Override
    @Transactional
    public JSONObject submitToReview(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> folderEquipBeans = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (folderEquipBeans.isEmpty()) {
            return req;
        }
        List<Long> ids = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
//        folderEquipBeans = this.selectListByIds(ids);
        List<LimsPjTaskBean> taskBeans = limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderEquipId", ids).filter(MatchPattern.OR));
        if (taskBeans.stream().anyMatch(t -> StringUtils.isBlank(t.getFinalResult()))) {
            req.put("flag", false);
            req.put("message", I18nHelper.getMessage("BASEMODULE.PJ_FOLDER_RESULT_SUBMIT"));
            return req;
        }

        LimsPjFolderEquipBean update = new LimsPjFolderEquipBean();
        update.setStatus("audit");
        getDao().updateByIds(update, ids, "status");

        limsAuditRecordService.insertAuditRecords(ids, "T_LIMS_PJ_FOLDER_EQUIP", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), "");

        taskBeans.forEach(t -> {
            t.setStatus("audit");
        });
        limsPjTaskService.getDao().fastUpdate(taskBeans, "status");

        return req;
    }

    @Override
    @Transactional
    public JSONObject submitReview(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> from = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (from.isEmpty()) {
            return req;
        }
        List<Long> ids = from.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
        List<LimsPjFolderEquipBean> folderEquipBeans = this.selectListByIds(ids);
        List<Long> folderIds = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getFolderId).collect(Collectors.toList());
        List<LimsPjFolderEquipBean> folderEquipAll = this.selectListByFilter(SearchFilter.instance().match("folderId", folderIds).filter(MatchPattern.OR));

        List<Long> willDoneFolderIds = new ArrayList<>();
        List<LimsPjTaskBean> updateBy = new ArrayList<>();
        folderIds.forEach(fi -> {
            List<LimsPjFolderEquipBean> temp = folderEquipBeans.stream().filter(fe -> fe.getFolderId().equals(fi)).collect(Collectors.toList());
            List<LimsPjFolderEquipBean> thisFolderAllEpts = folderEquipAll.stream().filter(fe -> fe.getFolderId().equals(fi)).collect(Collectors.toList());
            boolean canDone = true;
            if (thisFolderAllEpts.stream().anyMatch(tf -> !tf.getStatus().equals("audit") && !tf.getStatus().equals("done"))) {
                canDone = false;
            } else {

            }
            List<LimsPjFolderEquipBean> needDoneFolderEquipts = folderEquipAll.stream().filter(fe -> fe.getFolderId().equals(fi) && fe.getStatus().equals("audit")).collect(Collectors.toList());
            if (canDone && needDoneFolderEquipts.stream().allMatch(nd -> temp.stream().anyMatch(te -> te.getId().equals(nd.getId())))) {
                willDoneFolderIds.add(fi);
            }
            temp.forEach(t -> {
                LimsPjTaskBean update = new LimsPjTaskBean();
                update.setFolderEquipId(t.getId());
                update.setStatus("done");
                updateBy.add(update);
            });
        });
        limsPjTaskService.getDao().update(updateBy, Collections.singletonList("status"), "folderEquipId");

        LimsPjFolderEquipBean update = new LimsPjFolderEquipBean();
        update.setStatus("done");
        getDao().updateByIds(update, ids, "status");

        limsAuditRecordService.insertAuditRecords(ids, "T_LIMS_PJ_FOLDER_EQUIP", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_AUDIT"), "提交", "");

        if (!willDoneFolderIds.isEmpty()) {
            List<LimsPjReportBean> reportBeans = new ArrayList<>();

            LimsPjFolderBean updateFolder = new LimsPjFolderBean();
            updateFolder.setStatus("done");
            limsPjFolderService.getDao().updateByIds(updateFolder, willDoneFolderIds, "status");

            List<LimsPjFolderEquipBean> folderEquipBeanList = this.selectListByFilter(SearchFilter.instance().match("folderId", willDoneFolderIds).filter(MatchPattern.OR));

            List<LimsPjFolderBean> reportFolders = limsPjFolderService.selectListByParam(SearchFilter.instance().match("id", willDoneFolderIds).filter(MatchPattern.OR));
            List<Long> productIds = reportFolders.stream().map(LimsPjFolderBean::getProductId).distinct().collect(Collectors.toList());
            List<LimsReportClientProductBean> reportClientProductBeans = limsReportClientProductService.selectListByFilter(SearchFilter.instance().match("productId", productIds).filter(MatchPattern.OR), Order.desc("id"));
            List<Long> tempIds = reportClientProductBeans.stream().map(LimsReportClientProductBean::getReportTemplateId).collect(Collectors.toList());
            List<LimsProductReportTemplateBean> productReportTemplateBeans = limsProductReportTemplateService.selectListByIds(tempIds);
            reportFolders.forEach(rf -> {
                LimsPjReportBean reportBean = new LimsPjReportBean();
                reportBean.setId(ApplicationContextHelper.getNextIdentity());
                reportBean.setReportNo(ApplicationContextHelper.getNextSequence(limsPjReportService.getDao().getTable()));

                reportBean.setBatchId(rf.getBatchId());
                reportBean.setBatchCode(rf.getBatchCode());
                reportBean.setSampleIds(rf.getSampleId().toString());
                reportBean.setSampleCodes(rf.getSampleCode());
                reportBean.setFolderIds(rf.getId().toString());
                reportBean.setFolderCodes(rf.getFolderCode());

                reportBean.setProductId(rf.getProductId());
                reportBean.setProductCode(rf.getProductCode());
                reportBean.setProductName(rf.getProductName());

                reportBean.setType("PJ");
                // 说是要取结果录入的状态，但是结果录入不止一个
//                reportBean.setResultStatus(rf.getStatus());

                reportBean.setResultStatus("normal");
                AtomicInteger abnormalNum = new AtomicInteger(0);
                AtomicInteger dangerNum = new AtomicInteger(0);
                folderEquipBeanList.stream().filter(fe -> fe.getFolderId().equals(rf.getId())).forEach(fe -> {
                    if ("danger".equals(fe.getResultStatus())) {
                        dangerNum.getAndIncrement();
                    } else if ("abnormal".equals(fe.getResultStatus())) {
                        abnormalNum.getAndIncrement();
                    } else {

                    }
                });
                if (dangerNum.get() > 0) {
                    reportBean.setResultStatus("danger");
                } else if (abnormalNum.get() > 0) {
                    reportBean.setResultStatus("abnormal");
                }

                // 取报告模板
                if (StringUtils.isBlank(rf.getExt$Item("CUSTOMERCODE"))) {

                } else {
                    List<LimsReportClientProductBean> sameProducts = reportClientProductBeans.stream().filter(rcp -> rcp.getProductId().equals(rf.getProductId())).collect(Collectors.toList());
                    if (!sameProducts.isEmpty()) {
                        Optional<LimsReportClientProductBean> sameClientCode = sameProducts.stream().filter(sp -> StringUtils.equals(sp.getClientCode(), rf.getExt$Item("CUSTOMERCODE"))).findFirst();
                        if (sameClientCode.isPresent()) {
                            LimsReportClientProductBean rcp = sameClientCode.get();
                            productReportTemplateBeans.stream().filter(prt -> prt.getId().equals(rcp.getReportTemplateId())).findAny().ifPresent(prt -> {
                                reportBean.setReportTemplateId(prt.getTemplateId());
                                reportBean.setReportTemplateCode(prt.getTemplateCode());
                                reportBean.setReportTemplateName(prt.getTemplateName());
                            });
                        } else {
                            LimsReportClientProductBean rcp = sameProducts.get(0);
                            productReportTemplateBeans.stream().filter(prt -> prt.getId().equals(rcp.getReportTemplateId())).findAny().ifPresent(prt -> {
                                reportBean.setReportTemplateId(prt.getTemplateId());
                                reportBean.setReportTemplateCode(prt.getTemplateCode());
                                reportBean.setReportTemplateName(prt.getTemplateName());
                            });
                        }
                    }
                }

                reportBeans.add(reportBean);
            });

            if (!reportBeans.isEmpty()) {
                limsPjReportService.getDao().fastInsert(reportBeans);
            }
        }

        return req;
    }

    @Override
    @Transactional
    public JSONObject backToResult(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> folderEquipBeans = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (folderEquipBeans.isEmpty()) {
            return req;
        }
        List<Long> ids = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
//        folderEquipBeans = this.selectListByIds(ids);
        List<LimsPjTaskBean> taskBeans = limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderEquipId", ids).filter(MatchPattern.OR));

        LimsPjFolderEquipBean update = new LimsPjFolderEquipBean();
        update.setStatus("logged");
        getDao().updateByIds(update, ids, "status");

        limsAuditRecordService.insertAuditRecords(ids, "T_LIMS_PJ_FOLDER_EQUIP", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_AUDIT"), I18nHelper.getMessage("MODULE.PJ.RESULT_AUDIT.RETURNBACK"), "");

        taskBeans.forEach(t -> {
            t.setStatus("logged");
        });
        limsPjTaskService.getDao().fastUpdate(taskBeans, "status");

        return req;
    }

    @Override
    @Transactional
    public JSONObject updateFormula(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> from = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (from.isEmpty()) {
            return req;
        }
        List<Long> ids = from.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
//        List<LimsPjFolderEquipBean> folderEquipBeans = this.selectListByIds(ids);
        List<LimsPjTaskBean> taskBeans = limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderEquipId", ids).filter(MatchPattern.OR));
        if (!taskBeans.isEmpty()) {
            List<Long> productPurposeIds = taskBeans.stream().map(LimsPjTaskBean::getPurposeId).distinct().collect(Collectors.toList());
            List<LimsProductMainPuposeBean> mainPuposeBeans = productMainPuposeService.selectListByIds(productPurposeIds);
            taskBeans.forEach(t -> {
                mainPuposeBeans.stream().filter(mp -> mp.getId().equals(t.getPurposeId())).findAny().ifPresent(mp -> {
                    t.setFormula(mp.getFormula());
                });
            });
            limsPjTaskService.getDao().update(taskBeans, Collections.singletonList("formula"), "id");
        }
        PjTaskComputingEngine.getEngine(ids).compute();
        return req;
    }

    @Override
    public List<LimsPjTaskBean> purposeSelections(Long id) {
        return limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderEquipId", id).filter(MatchPattern.EQ));
    }

    @Override
    @Transactional
    public JSONObject submitAbnormal(RestJsonWrapperBean wrapperBean) {
        JSONObject req = new JSONObject();
        req.put("flag", true);
        List<LimsPjFolderEquipBean> from = wrapperBean.parse(LimsPjFolderEquipBean.class);
        if (from.isEmpty()) {
            return req;
        }
        List<Long> ids = from.stream().map(LimsPjFolderEquipBean::getId).collect(Collectors.toList());
        List<LimsPjFolderEquipBean> folderEquipBeans = this.selectListByIds(ids);

        List<Long> folderIds = folderEquipBeans.stream().map(LimsPjFolderEquipBean::getFolderId).distinct().collect(Collectors.toList());
        LimsPjFolderBean updateFolder = new LimsPjFolderBean();
        updateFolder.setStatus("abnormal");
        limsPjFolderService.getDao().updateByIds(updateFolder, folderIds, "status");
        limsAuditRecordService.insertAuditRecords(folderIds, "T_LIMS_PJ_FOLDER", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_AUDIT"), I18nHelper.getMessage("MODULE.PJ.RESULT_AUDIT.STOP"), "");

        //TODO 暂时不明确，如果同一个folder下还有别的仪器任务，要不要也一起进入异常
        List<LimsPjTaskBean> taskBeans = limsPjTaskService.selectListByFilter(SearchFilter.instance().match("folderEquipId", ids).filter(MatchPattern.OR));
        List<Long> taskIds = taskBeans.stream().map(LimsPjTaskBean::getId).collect(Collectors.toList());
        LimsPjTaskBean updateTask = new LimsPjTaskBean();
        updateTask.setStatus("abnormal");
        limsPjTaskService.getDao().updateByIds(updateTask, taskIds, "status");

        LimsPjFolderEquipBean folderEquipBean = new LimsPjFolderEquipBean();
        folderEquipBean.setStatus("abnormal");
        getDao().updateByIds(folderEquipBean, ids, "status");
        limsAuditRecordService.insertAuditRecords(ids, "T_LIMS_PJ_FOLDER_EQUIP", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.RESULT_AUDIT"), I18nHelper.getMessage("MODULE.PJ.RESULT_AUDIT.STOP"), "");

        return req;
    }
}
